`include "common.svh"

module dtcm (
    input          clk,
    input          rst,
    //Memory Req Port
    input          req_valid,
    input  MEM_REQ req,
    output         req_ready,
    input          req_kill_prev,
    //Load early wakeup
    output         early_wakeup_valid,
    output PRF_IDX early_wakeup_prf_idx,
    //Memory Rsp Port
    output         rsp_valid,
    output MEM_RSP rsp,
    input          rsp_ready
);

  localparam AW = $clog2(`DTCM_SIZE / 8);
  localparam DW = 64;
  logic          cs;
  logic          we;
  logic [DW-1:0] wmask;
  logic [AW-1:0] addr;
  logic [DW-1:0] wdata;
  logic [DW-1:0] rdata;
  mask_ram_1rw #(DW, AW, 1, `DTCM_IMAGE) inst_mask_ram (.*);

  word_t load_data;

  logic s1_rsp_valid, s1_rsp_ready;
  MEM_RSP s1_rsp;
  /* verilator lint_off UNUSEDSIGNAL */
  MEM_REQ s1_req;
  /* verilator lint_on UNUSEDSIGNAL */
  wire s1_rsp_fire = s1_rsp_valid & s1_rsp_ready;
  decouple inst_decouple_s1 (
      .i_valid(req_valid),
      .i_ready(req_ready),
      .o_valid(s1_rsp_valid),
      .o_ready(s1_rsp_ready | req_kill_prev),
      .*
  );
  decouple inst_decouple_rsp (
      .i_valid(s1_rsp_valid),
      .i_ready(s1_rsp_ready),
      .o_valid(rsp_valid),
      .o_ready(rsp_ready),
      .rst(rst | req_kill_prev),
      .*
  );
  wire req_fire = req_valid & req_ready;

  word_t req_mask;
  word_t req_wdata;
  always_comb begin
    req_mask = 'b0;
    case (req.size)
      'b1: req_mask = 64'hff << {req.addr[2:0], 3'b0};
      'b10: req_mask = 64'hffff << {req.addr[2:1], 4'b0};
      'b100: req_mask = 64'hffffffff << {req.addr[2:2], 5'b0};
      'b1000: req_mask = 64'hffffffffffffffff;
    endcase
    req_wdata = 'b0;
    case (req.size)
      'b1: req_wdata = {8{req.data[7:0]}};
      'b10: req_wdata = {4{req.data[15:0]}};
      'b100: req_wdata = {2{req.data[31:0]}};
      'b1000: req_wdata = req.data[63:0];
    endcase
    load_data = 'b0;
    case (s1_req.size)
      'b1: load_data[7:0] = rdata[{s1_req.addr[2:0], 3'b0}+:8];
      'b10: load_data[15:0] = rdata[{s1_req.addr[2:1], 4'b0}+:16];
      'b100: load_data[31:0] = rdata[{s1_req.addr[2:2], 5'b0}+:32];
      'b1000: load_data = rdata;
    endcase

  end

  assign cs = 'b1;
  assign we = req_fire & req.cmd == MEM_WRITE;
  assign wmask = req_mask;
  assign addr = req.addr[AW-1+3:3];
  assign wdata = req_wdata;
  always_ff @(posedge clk) begin
    if (req_fire) begin
      s1_rsp.rob_idx <= req.rob_idx;
      s1_rsp.prf_idx <= req.prf_idx;
      s1_rsp.has_rd <= req.has_rd;
      s1_rsp.has_data <= 'b0;
      s1_rsp.data <= 'b0;
      if (req.cmd == MEM_READ) begin
        // s1_rsp.data <= mem[req.addr[AW-1:3]];  //mem_read(req.addr, {4'b0, req.size});
        s1_rsp.has_data <= 'b1;
      end else if (req.cmd == MEM_WRITE) begin
        // mem[req.addr[AW-1:3]] <= (mem[req.addr[AW-1:3]] & ~req_mask ) | (req_wdata & req_mask);  //mem_write(req.addr, {4'b0, req.size}, req.data);
      end
      s1_req <= req;
    end
    if (s1_rsp_fire) begin
      rsp <= s1_rsp;
      rsp.data <= load_data;
      if (s1_req.cmd == MEM_READ) begin
        if (s1_req.sign) begin
          case (s1_req.size)
            4'b0001: rsp.data[63:8] <= {56{load_data[7]}};
            4'b0010: rsp.data[63:16] <= {48{load_data[15]}};
            4'b0100: rsp.data[63:32] <= {32{load_data[31]}};
            default: ;
          endcase
        end
      end
    end
  end
  assign early_wakeup_valid   = s1_rsp_valid & s1_rsp_ready & ~req_kill_prev & (s1_req.cmd == MEM_READ);
  assign early_wakeup_prf_idx = s1_req.prf_idx;

endmodule
